﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

using System.Net;
using System.Net.Sockets;


using RetroNET.Network;

namespace RetroNET
{
    public partial class RetroNETCore
    {
		  const string version = "0.001a";

        Socket mainListenSock;

        private byte[] data = new byte[2048];
        static ManualResetEvent mreClientListening = new ManualResetEvent(false);

        private int listenPort = 9600;

        List<RNClient> clients = new List<RNClient>();

		  public HandleClientInputDelegate delHandleClientInput = null;
		  public HandleRemoteDataDelegate delHandleRemodeData = null;
		  public OnClientConnectedDelegate delOnClientConnected = null;

        public void Setup()
        {

        }

		  internal void Start()
		  {
			  OpenListenSocket();

		  }

        public void OpenListenSocket()
        {
            IPHostEntry localhost = Dns.GetHostEntry(Dns.GetHostName());
            IPEndPoint endpoint = new IPEndPoint(new IPAddress(new byte[4] {0,0,0,0}), listenPort);
            mainListenSock = new Socket(endpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            try
            {
                mainListenSock.Bind(endpoint);
                mainListenSock.Listen(10);

					 Console.WriteLine("RetroNET initialization complete.");
					 Console.WriteLine("Now listening on port " + listenPort + "...");


                while (true)
                {
                    mreClientListening.Reset();

                    mainListenSock.BeginAccept(new AsyncCallback(AcceptConnection), mainListenSock);

                    mreClientListening.WaitOne();

                }

            }
            catch (Exception ex)
            {
                Console.WriteLine("[SOCKET] Error: " + ex);
            }

        }

        void AcceptConnection(IAsyncResult result)
        {
            mreClientListening.Set();

            // Set this socket to a new RNClient
            RNClient newclient = new RNClient();
            newclient.sockIn = ((Socket)result.AsyncState).EndAccept(result); 

            // Set us up to start listening to this client
            newclient.ListenToClient(this);

            // and add us to the list...
            clients.Add(newclient); 

            // And mention it in the console
            Console.WriteLine("Client connected from " + newclient.sockIn.RemoteEndPoint.ToString());

				if (delOnClientConnected != null) delOnClientConnected(newclient);
				
        }

        public void SendDataToClient(RNClient client, string msg, bool addCRLF = true)  // Send a message to the client asynchronously
        {
			  if (client.sockIn == null || !client.sockIn.Connected) return;

            byte[] msgBytes = Encoding.ASCII.GetBytes(msg + (addCRLF ? "\r\n" : "")); // we add the CRLF here, so don't send it in msg (unless you want multiples)
            client.sockIn.BeginSend(msgBytes, 0, msgBytes.Length, SocketFlags.None, new AsyncCallback(cbSentDataToClient), client);
        }
		  public void SendDataToClient(RNClient client, byte[] data, bool addCRLF = true)  // Will send all of data[] to the client, so trim it before you send it!
		  {
			  if (client.sockIn == null || !client.sockIn.Connected) return;
			  //byte[] msgBytes = Encoding.ASCII.GetBytes(client.recvbuffer.Take(numBytes).ToArray() + (addCRLF ? "\r\n" : "")); // we add the CRLF here, so don't send it in msg (unless you want multiples)
			  client.sockIn.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(cbSentDataToClient), client);
		  }



        void ClientCleanup(RNClient client)
        {
            client.Shutdown();
            if (clients.Contains(client)) clients.Remove(client);

        }




	 }

 }
